package cn.openea.perpartner.componet.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.openea.perpartner.common.core.exception.ServiceException;
import cn.openea.perpartner.componet.rabbit.domain.BusinessDto;
import cn.openea.perpartner.componet.rabbit.factory.BusinessServiceFactory;
import cn.openea.perpartner.componet.rabbit.service.BusinessService;
import cn.openea.perpartner.componet.rabbit.service.impl.PublisherService;
import cn.openea.perpartner.componet.rabbit.service.impl.sms.AliyunSmsPublisher;
import cn.openea.perpartner.componet.web.entity.SmsHistory;
import cn.openea.perpartner.componet.web.entity.SmsSign;
import cn.openea.perpartner.componet.web.entity.SmsTemplate;
import cn.openea.perpartner.componet.web.entity.dto.sms.BatchDto;
import cn.openea.perpartner.componet.web.entity.dto.sms.SendDetail;
import cn.openea.perpartner.componet.web.entity.dto.sms.SendTo;
import cn.openea.perpartner.componet.web.entity.dto.sms.SmsDto;
import cn.openea.perpartner.componet.web.entity.vo.SmsTemplateVo;
import cn.openea.perpartner.componet.web.mapper.SmsHistoryMapper;
import cn.openea.perpartner.componet.web.mapper.SmsSignMapper;
import cn.openea.perpartner.componet.web.mapper.SmsTemplateMapper;
import cn.openea.perpartner.componet.web.service.ISmsBlacklistService;
import cn.openea.perpartner.componet.web.service.ISmsService;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.*;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * (SmsHistory)表服务实现类
 *
 * @author Weird077
 * @since 2023-04-07 12:28:34
 */
@Slf4j
@Service
public class SmsServiceImpl extends ServiceImpl<SmsHistoryMapper, SmsHistory> implements ISmsService, BusinessService {


    @Autowired
    private ConcurrentHashMap<String, Object> cache;
    @Autowired
    private IAcsClient acsClient;
    @Autowired
    private SmsTemplateMapper smsTemplateMapper;
    @Autowired
    private SmsSignMapper smsSignMapper;
    @Autowired
    private PublisherService publisherService;
    @Autowired
    private AliyunSmsPublisher aliyunSmsPublisher;
    @Autowired
    private ISmsBlacklistService smsBlacklistService;


    @Override
    public List<SmsTemplate> selectTemplateList(SmsTemplateVo templateVo) {
        LambdaQueryWrapper<SmsTemplate> wrapper = Wrappers.lambdaQuery();
        if (templateVo == null) {
            return smsTemplateMapper.selectList(wrapper);
        }
        if (StrUtil.isNotBlank(templateVo.getTemplateId())) {
            wrapper.eq(SmsTemplate::getTemplateId, templateVo.getTemplateId());
        }
        if (StrUtil.isNotBlank(templateVo.getName())) {
            wrapper.like(SmsTemplate::getName, templateVo.getName());
        }
        return smsTemplateMapper.selectList(wrapper);
    }

    @Override
    public boolean deleteSmsTemplate(List<Long> idList) {
        return smsTemplateMapper.deleteBatchIds(idList) > 0;
    }

    @Override
    public boolean saveSmsTemplate(SmsTemplate smsTemplate) {
        if (smsTemplate.getId() != null) {
            return smsTemplateMapper.updateById(smsTemplate) > 0;
        }
        return smsTemplateMapper.insert(smsTemplate) > 0;
    }

    @Override
    public List<SmsHistory> selectHistoryList(SmsHistory sms) {
        LambdaQueryWrapper<SmsHistory> wrapper = Wrappers.lambdaQuery();
        if (StrUtil.isNotBlank(sms.getPhoneNumber())) {
            wrapper.like(SmsHistory::getPhoneNumber, sms.getPhoneNumber());
        }
        if (StrUtil.isNotBlank(sms.getSendTo())) {
            wrapper.like(SmsHistory::getSendTo, sms.getSendTo());
        }
        if (StrUtil.isNotBlank(sms.getUserId())) {
            wrapper.like(SmsHistory::getUserId, sms.getUserId());
        }
        if (StrUtil.isNotBlank(sms.getTemplateCode())) {
            wrapper.like(SmsHistory::getTemplateCode, sms.getTemplateCode());
        }
        wrapper.orderByDesc(SmsHistory::getCreateTime);
        return list(wrapper);
    }

    @Override
    public boolean sendMsg(SmsDto smsDto) {
        BusinessDto businessDto = BusinessDto.builder()
                .delayTime(0)
                .beanName("smsService")
                .params(BeanUtil.toBean(smsDto, JSONObject.class))
                .build();
        return publisherService.execute(businessDto);
    }

    @Override
    public boolean batchSendMsg(SmsDto smsDto) {
        return aliyunSmsPublisher.batchSendMsgToMeilyUser(smsDto);
    }

    @Override
    public QuerySendDetailsResponse QuerySendDetails(SendDetail sendDetail) {
        try {
            QuerySendDetailsRequest request = new QuerySendDetailsRequest();
            request.setPhoneNumber(sendDetail.getPhoneNumber());
            request.setBizId(sendDetail.getBizId());
            request.setSendDate(sendDetail.getSendDate());
            request.setCurrentPage(sendDetail.getCurrentPage());
            request.setPageSize(sendDetail.getPageSize());
            QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);
            if (querySendDetailsResponse.getCode() != null && querySendDetailsResponse.getCode().equals("OK")) {
                return querySendDetailsResponse;
            }
        } catch (ClientException e) {
            log.error("查询短信发送明细失败", e);
        }
        return null;
    }

    @Override
    public boolean executeSendBatchMsg(BatchDto smsDto) {
        SmsTemplate template = (SmsTemplate) cache.get(smsDto.getTemplateCode());
        if (BeanUtil.isEmpty(template)) {
            template = smsTemplateMapper.selectOne(Wrappers.<SmsTemplate>lambdaQuery()
                    .eq(SmsTemplate::getTemplateId, smsDto.getTemplateCode()));
            cache.put(smsDto.getTemplateCode(), template);
        }
        List<SendTo> sendToList = smsDto.getSendParam();
        List<SmsHistory> smsHistoryList = new ArrayList<>();
        //发送阿里云短信
        SendBatchSmsRequest batchSmsRequest = new SendBatchSmsRequest();
        batchSmsRequest.setTemplateCode(template.getTemplateId());
        //分批发送,批量上限100个手机号
        int batchSize = 100;
        int totalSize = sendToList.size();
        for (int i = 0; i < totalSize; i += batchSize) {
            int endIndex = Math.min(i + batchSize, totalSize);
            List<SendTo> subList = sendToList.subList(i, endIndex)
                    .parallelStream().filter(item -> !smsBlacklistService.isExist(item.getPhoneNumber()))
                    .collect(Collectors.toList());// 过滤黑名单数据
            List<String> phoneList = subList.parallelStream()
                    .map(SendTo::getPhoneNumber)
                    .collect(Collectors.toList());
            StringBuffer signNameJson = new StringBuffer();
            StringBuffer templateParamJson = new StringBuffer();
            signNameJson.append("[");
            templateParamJson.append("[");
            for (int j = 0; j < phoneList.size(); j++) {
                signNameJson.append("'").append(template.getSignName()).append("',");
                templateParamJson.append("'").append(smsDto.getTemplateParam()).append(",");
            }
            String signName = signNameJson.toString();
            String templateParam = templateParamJson.toString();
            signName = signName.substring(0, signName.length() - 1).concat("]");
            templateParam = templateParam.substring(0, templateParam.length() - 1).concat("]");
            batchSmsRequest.setSignNameJson(signName);
            batchSmsRequest.setTemplateParamJson(templateParam);
            batchSmsRequest.setPhoneNumberJson(phoneList.toString());
            try {
                SendBatchSmsResponse batchSmsResponse = acsClient.getAcsResponse(batchSmsRequest);
                //保存发送记录
                for (SendTo sendTo : subList) {
                    SmsHistory smsHistory = SmsHistory.builder()
                            .templateCode(template.getTemplateId())
                            .templateParam(smsDto.getTemplateParam())
                            .sendTo(sendTo.getSendTo())
                            .phoneNumber(sendTo.getPhoneNumber())
                            .userId(smsDto.getUserId())
                            .smsBody(template.getContent())
                            .signName(template.getName())
                            .responseCode(batchSmsResponse.getCode())
                            .responseMsg(batchSmsResponse.getMessage())
                            .bizId(batchSmsResponse.getBizId())
                            .build();
                    if ("OK".equals(batchSmsResponse.getCode())) {
                        smsHistory.setSendFlag("1");
                    } else {
                        smsHistory.setSendFlag("0");
                    }
                    smsHistoryList.add(smsHistory);
                }
            } catch (ClientException e) {
                log.error("批量发送短信异常", e);
                return false;
            }
        }
        return saveBatch(smsHistoryList);
    }

    @Override
    public SmsTemplate selectTemplateById(String id) {
        if (StringUtils.isBlank(id)) {
            return null;
        }
        return smsTemplateMapper.selectById(id);
    }

    @Override
    public SmsTemplate selectTemplateByCode(String code) {
        if (StringUtils.isBlank(code)) {
            return null;
        }
        LambdaQueryWrapper<SmsTemplate> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SmsTemplate::getTemplateId, code);
        return smsTemplateMapper.selectOne(wrapper);
    }

    @Override
    public List<SmsSign> selectSignList(SmsSign sign) {
        LambdaQueryWrapper<SmsSign> wrapper = Wrappers.lambdaQuery();
        if (StrUtil.isNotBlank(sign.getSignName())) {
            wrapper.like(SmsSign::getSignName, sign.getSignName());
        }
        if (StrUtil.isNotBlank(sign.getSignSource())) {
            wrapper.like(SmsSign::getSignSource, sign.getSignSource());
        }
        if (StrUtil.isNotBlank(sign.getUseType())) {
            wrapper.like(SmsSign::getUseType, sign.getUseType());
        }
        if (StrUtil.isNotBlank(sign.getLinkThird())) {
            wrapper.eq(SmsSign::getLinkThird, sign.getLinkThird());
        }
        if (StrUtil.isNotBlank(sign.getThreeInOne())) {
            wrapper.eq(SmsSign::getThreeInOne, sign.getThreeInOne());
        }
        if (StrUtil.isNotBlank(sign.getStatus())) {
            wrapper.eq(SmsSign::getStatus, sign.getStatus());
        }
        wrapper.orderByDesc(SmsSign::getCreateTime);
        return smsSignMapper.selectList(wrapper);
    }

    @Override
    public void saveSmsSign(SmsSign sign) {
        // 参数校验
        String msg = sign.checkParams();
        if (StringUtils.isNotBlank(msg)) {
            throw new ServiceException(msg);
        }
        // 判断这个签名名称是否存在
        SmsSign smsSign = smsSignMapper.selectOne(new LambdaQueryWrapper<SmsSign>()
                .eq(SmsSign::getSignName, sign.getSignName()));
        if (sign.getId() == null && smsSign != null) {
            throw new ServiceException("签名名称已存在");

        }
        if (sign.getId() != null && (smsSign != null && !smsSign.getId().equals(sign.getId()))) {
            throw new ServiceException("签名名称已存在");
        }
        if (sign.getId() == null) {
            smsSignMapper.insert(sign);
            return;
        }
        smsSignMapper.updateById(sign);

    }

    @Override
    public SmsSign selectSignById(String id) {
        return smsSignMapper.selectById(id);
    }

    @Override
    public int deleteSmsSign(List<Long> idList) {
        return smsSignMapper.deleteBatchIds(idList);
    }

    @Override
    public TimerTask execute(BusinessDto business) {
        return new TimerTask() {
            @Override
            public void run() {
                try {
                    SmsDto sms = BeanUtil.toBean(business.getParams(), SmsDto.class);
                    if (smsBlacklistService.isExist(sms.getPhoneNumber())){
                        // 在黑名单中
                        return;
                    }
                    SmsTemplate template = (SmsTemplate) cache.get(sms.getTemplateCode());
                    if (BeanUtil.isEmpty(template)) {
                        template = smsTemplateMapper.selectOne(Wrappers.<SmsTemplate>lambdaQuery().eq(SmsTemplate::getTemplateId, sms.getTemplateCode()));
                        cache.put(sms.getTemplateCode(), template);
                    }
                    SendSmsRequest request = new SendSmsRequest();
                    request.setPhoneNumbers(sms.getPhoneNumber());
                    request.setSignName(template.getName());
                    request.setTemplateCode(sms.getTemplateCode());
                    request.setTemplateParam(sms.getTemplateParam());
                    request.setSignName(template.getSignName());
                    SendSmsResponse response = acsClient.getAcsResponse(request);
                    SmsHistory smsHistory = SmsHistory.builder()
                            .phoneNumber(sms.getPhoneNumber())
                            .templateCode(sms.getTemplateCode())
                            .templateParam(sms.getTemplateParam())
                            .sendTo(sms.getSendTo())
                            .userId(sms.getUserId())
                            .smsBody(template.getContent())
                            .signName(template.getName())
                            .responseCode(response.getCode())
                            .responseMsg(response.getMessage())
                            .bizId(response.getBizId())
                            .build();
                    if ("OK".equals(response.getCode())) {
                        smsHistory.setSendFlag("1");
                    } else {
                        smsHistory.setSendFlag("0");
                    }
                    save(smsHistory);
                } catch (ClientException e) {
                    e.printStackTrace();
                }

            }
        };
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        BusinessServiceFactory.register("smsService", this);
    }
}

